Перейти к основному содержимому

CSV - кодировки, импорт и экспорт

· 2 мин. чтения

Comma Separated Values - типичный способ экспорта табличных данных, но далеко не стандартный в плане совместимости между Excel, php и другими источниками данных. Надо читать RFC, и пробовать всё на практике

Самое наглядное - если вы думали что данные достаточно через запятую перечислить, то если вы сохраните простой текстовый файл с такими данными:

ID,name 1,Mac'duck

То в Excel получите

Тому несколько причин

  • Отсутсвие utf8
  • Разные символы разделения данных (табы вместо запятых)
  • Особые символы (", n , r) должны очищаться что-бы не побить линейную разметку
  • fgetcsv()
  • Данные лучше помещать в двойные кавычки, а сами двойные кавычки в данных эскейпятся повторением:
    $value = str_replace('"', '""', $value);
    $value = '"' . $value . '"' . ",";

Mysql

SELECT id, name, email INTO OUTFILE '/tmp/result.csv'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY 'n'
FROM users WHERE 1

 

Экспорт

header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Cache-Control: public');
header('Content-Description: File Transfer');
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename=SomeFile_' .time(). '.csv;');
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.strlen($strCSV));

mb_internal_encoding("UTF-8");

$strCSV= chr(255) . chr(254) . mb_convert_encoding($strCSV, "UTF-16LE", "UTF-8");

 

Импорт

uiyi

$sCSVFileData = file_get_contents($aFile['tmp_name']);
if (mb_detect_encoding($sCSVFileData)) {
$sCSVFileData = mb_convert_encoding(mb_substr($sCSVFileData, 2, mb_strlen($sCSVFileData)), "UTF-8", mb_detect_encoding($sCSVFileData));
}
else {
$sCSVFileData = mb_convert_encoding(mb_substr($sCSVFileData, 2, mb_strlen($sCSVFileData)), "UTF-8", "UTF-16LE");
}

$aCSVLines = explode("rn", $sCSVFileData);

for ($i = 0; $i < count($aCSVLines); $i++) {
if ($i > 0) {
$arrData[] = getCSVValues($aCSVLines[$i], "t");
}
}

function getCSVValues($sString, $sSeparator = ",") {
$sString = str_replace('""', "'", $sString);
$aBits = explode($sSeparator, $sString);
$aElements = array();
for ($i = 0; $i < count($aBits); $i++) {
if (($i % 2) == 1) {
$aElements[] = $aBits[$i];
}
else {
$sRest = $aBits[$i];
$sRest = preg_replace("/^" . $sSeparator . "/", "", $sRest);
$sRest = preg_replace("/" . $sSeparator . "$/", "", $sRest);
$aElements = array_merge($aElements, explode($sSeparator, $sRest));
}
}

return $aElements;
}